package org.xlx.xlx_oa.attendance.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.xlx.xlx_oa.attendance.convertor.AttendanceConvertor;
import org.xlx.xlx_oa.attendance.domain.AttendanceApply;
import org.xlx.xlx_oa.attendance.domain.dto.AttendanceApplyDto;
import org.xlx.xlx_oa.attendance.domain.vo.AttendanceApplyVo;
import org.xlx.xlx_oa.attendance.mapper.AttendanceApplyMapper;
import org.xlx.xlx_oa.common.BusinessException;
import org.xlx.xlx_oa.common.Constant;
import org.xlx.xlx_oa.common.enums.ApplyTypeEnums;
import org.xlx.xlx_oa.common.enums.ProcessStatusEnums;
import org.xlx.xlx_oa.common.enums.ProcessTypeEnums;
import org.xlx.xlx_oa.role_user.domain.AdmDepartment;
import org.xlx.xlx_oa.role_user.domain.AdmPosition;
import org.xlx.xlx_oa.role_user.domain.AdmProcess;
import org.xlx.xlx_oa.role_user.domain.AdmUser;
import org.xlx.xlx_oa.role_user.domain.dto.AdmProcessDto;
import org.xlx.xlx_oa.role_user.domain.vo.AuditVo;
import org.xlx.xlx_oa.role_user.mapper.AdmDepartmentMapper;
import org.xlx.xlx_oa.role_user.mapper.AdmPositionMapper;
import org.xlx.xlx_oa.role_user.mapper.AdmUserMapper;
import org.xlx.xlx_oa.role_user.service.AdmProcessService;
import org.xlx.xlx_oa.utils.ThreadLocalUtil;

import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;

@Service
public class AttendanceApplyService {
    private static final ProcessTypeEnums processType = ProcessTypeEnums.Attendance;
    private final AttendanceConvertor attendanceConvertor = AttendanceConvertor.INSTANCE;
    @Autowired
    private AttendanceApplyMapper attendanceApplyMapper;
    @Autowired
    private AdmProcessService admProcessService;
    @Autowired
    private AdmUserMapper userMapper;
    @Autowired
    private AdmDepartmentMapper departmentMapper;
    @Autowired
    private AdmPositionMapper positionMapper;

    /**
     * 新增申请信息，新增处理任务信息
     * 更新申请信息
     *
     * @param applyVo
     * @return
     */
    @Transactional
    public Boolean saveAttendanceApply(AttendanceApplyVo applyVo) {
        AttendanceApply attendanceApply = attendanceConvertor.convertVoToDomain(applyVo);
        if (Objects.isNull(attendanceApply.getId())) {
            attendanceApply.setProcessStatus(ProcessStatusEnums.Pending.name());
            attendanceApplyMapper.insert(attendanceApply);
            //check time >72
            Duration duration = Duration.between(attendanceApply.getStartTime(), attendanceApply.getEndTime());
            long hours = duration.toHours();
            boolean flag = hours > 72;
            Boolean process = admProcessService.createProcess(attendanceApply.getId(), processType, flag);
            AttendanceApply temp = attendanceApplyMapper.selectById(attendanceApply.getId());
            if (process) {
                temp.setProcessStatus(ProcessStatusEnums.Approve.name());
            } else {
                temp.setProcessStatus(ProcessStatusEnums.Processing.name());
            }
            attendanceApplyMapper.updateById(temp);
        } else {
            AttendanceApply temp = attendanceApplyMapper.selectById(attendanceApply.getId());
            if (!ProcessStatusEnums.Pending.name().equals(temp.getProcessStatus())) {
                throw new BusinessException("100007", "The application is under review and cannot be modified");
            }
            attendanceApplyMapper.updateById(attendanceApply);
        }
        return true;
    }

    /**
     * 审批考勤申请
     *
     * @param auditVo
     * @return
     */
    @Transactional
    public Boolean auditAttendanceApply(AuditVo auditVo) {
        AttendanceApply apply = attendanceApplyMapper.selectById(auditVo.getApplyId());
        String status = admProcessService.updateAuditProcess(auditVo, apply);
        apply.setProcessStatus(status);
        return attendanceApplyMapper.updateById(apply) > 0;
    }

    /**
     * 获取待审批考勤申请
     */
    public List<AttendanceApplyDto> getBeAuditList(AttendanceApplyVo applyVo) {
        Integer pageNum = applyVo.getPageNum();
        Integer pageSize = applyVo.getPageSize();
        List<AdmProcess> applyList = admProcessService.getApplyList(processType.name());
        HashMap<Long, String> map = new HashMap<>();
        if (applyList.size()==0){
            map.put(0L,"");
        }else {
            applyList.forEach(admProcess -> map.put(admProcess.getApplyId(),admProcess.getResult()));
        }
        Page<AttendanceApply> page = new Page<>(pageNum, pageSize);
        QueryWrapper<AttendanceApply> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .in(AttendanceApply::getId, map.keySet());
        if (applyVo.getProcessStatus() != null && (!"".equals(applyVo.getProcessStatus()))) {
            wrapper.lambda().eq(AttendanceApply::getProcessStatus, applyVo.getProcessStatus());
        }
        if (applyVo.getApplyType() != null && (!"".equals(applyVo.getApplyType()))) {
            wrapper.lambda().eq(AttendanceApply::getApplyType, applyVo.getApplyType());
        }
        attendanceApplyMapper.selectPage(page, wrapper);
        List<AttendanceApply> records = page.getRecords();
        List<AttendanceApplyDto> attendanceApplyDtos = attendanceConvertor.convertToDomainDtoList(records);
        attendanceApplyDtos.forEach(applyDto -> {
            applyDto.setTackleStatus(map.get(applyDto.getId()));
            this.supplyAttendApplyDto(applyDto);
        });
        return attendanceApplyDtos;
    }

    /**
     * 审批总数
     */
    public Integer getBeAuditedCount(AttendanceApplyVo applyVo) {
        List<AdmProcess> applyList = admProcessService.getApplyList(processType.name());
        HashMap<Long, String> map = new HashMap<>();
        if (applyList.size()==0){
            map.put(0L,"");
        }else {
            applyList.forEach(admProcess -> map.put(admProcess.getApplyId(),admProcess.getResult()));
        }
        QueryWrapper<AttendanceApply> wrapper = new QueryWrapper<>();
        wrapper.lambda()
                .in(AttendanceApply::getId, map.keySet());
        if (applyVo.getProcessStatus() != null && (!"".equals(applyVo.getProcessStatus()))) {
            wrapper.lambda().eq(AttendanceApply::getProcessStatus, applyVo.getProcessStatus());
        }
        if (applyVo.getApplyType() != null && (!"".equals(applyVo.getApplyType()))) {
            wrapper.lambda().eq(AttendanceApply::getApplyType, applyVo.getApplyType());
        }
        return attendanceApplyMapper.selectCount(wrapper);
    }

    /**
     * 审批详情
     *
     * @param applyId
     * @return
     */
    public List<AdmProcessDto> getApplyDetail(Long applyId) {
        return admProcessService.getListByApplyId(applyId, processType.name());
    }

    /**
     * 申请列表
     *
     * @param applyVo
     * @return
     */
    public List<AttendanceApplyDto> getApplyList(AttendanceApplyVo applyVo) {
        Integer pageNum = applyVo.getPageNum();
        Integer pageSize = applyVo.getPageSize();
        Object obj = ThreadLocalUtil.get(Constant.USERID);
        Long userId = (obj == null || "".equals(obj)) ? null : Long.valueOf(obj.toString());
        Page<AttendanceApply> page = new Page<>(pageNum, pageSize);
        QueryWrapper<AttendanceApply> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(AttendanceApply::getCreatedId, userId);
        if (applyVo.getProcessStatus() != null && (!"".equals(applyVo.getProcessStatus()))) {
            queryWrapper.lambda().eq(AttendanceApply::getProcessStatus, applyVo.getProcessStatus());
        }
        if (applyVo.getApplyType() != null && (!"".equals(applyVo.getApplyType()))) {
            queryWrapper.lambda().eq(AttendanceApply::getApplyType, applyVo.getApplyType());
        }
        attendanceApplyMapper.selectPage(page, queryWrapper);
        List<AttendanceApply> records = page.getRecords();
        List<AttendanceApplyDto> attendanceApplyDtos = attendanceConvertor.convertToDomainDtoList(records);
        attendanceApplyDtos.forEach(applyDto -> this.supplyAttendApplyDto(applyDto));
        return attendanceApplyDtos;
    }

    /**
     * 申请总数
     */
    public Integer getApplyCount(AttendanceApplyVo applyVo) {
        Object obj = ThreadLocalUtil.get(Constant.USERID);
        Long userId = (obj == null || "".equals(obj)) ? null : Long.valueOf(obj.toString());
        QueryWrapper<AttendanceApply> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(AttendanceApply::getCreatedId, userId);
        if (applyVo.getProcessStatus() != null && (!"".equals(applyVo.getProcessStatus()))) {
            queryWrapper.lambda().eq(AttendanceApply::getProcessStatus, applyVo.getProcessStatus());
        }
        return attendanceApplyMapper.selectCount(queryWrapper);
    }

    /**
     * 考勤补全
     */
    public void supplyAttendApplyDto(AttendanceApplyDto applyDto) {
        AdmUser user = userMapper.selectById(applyDto.getCreatedId());
        applyDto.setFirstName(user.getFirstName());
        applyDto.setMiddleName(user.getMiddleName());
        applyDto.setLastName(user.getLastName());
        if (user.getDepartmentId() != null && user.getDepartmentId() != 0) {
            AdmDepartment department = departmentMapper.selectById(user.getDepartmentId());
            applyDto.setDepartmentTitle(department.getTitle());
        }
        if (user.getPositionId() != null && user.getPositionId() != 0) {
            AdmPosition position = positionMapper.selectById(user.getPositionId());
            applyDto.setPositionTitle(position.getTitle());
        }
        if (applyDto.getTackleStatus()!=null&&(!"".equals(applyDto.getTackleStatus()))){
            ProcessStatusEnums tackleEnums = ProcessStatusEnums.valueOf(ProcessStatusEnums.class, applyDto.getTackleStatus());
            applyDto.setTackleStatusName(tackleEnums.getText());
        }
        ProcessStatusEnums statusEnums = ProcessStatusEnums.valueOf(ProcessStatusEnums.class, applyDto.getProcessStatus());
        applyDto.setProcessStatusName(statusEnums.getText());
        ApplyTypeEnums typeEnums = ApplyTypeEnums.valueOf(ApplyTypeEnums.class, applyDto.getApplyType());
        applyDto.setApplyTypeName(typeEnums.getText());
    }
}
